Skip to content

V4#18

Open
gunesahmet wants to merge 6 commits into
xmonader:masterfrom
gunesahmet:V4
Open

V4#18
gunesahmet wants to merge 6 commits into
xmonader:masterfrom
gunesahmet:V4

Conversation

@gunesahmet
Copy link
Copy Markdown

@gunesahmet gunesahmet commented Apr 4, 2026

feat: code completion, go-to-definition, ordinal auto-increment (v3.0 → v4.0)

Add three major features to the Cap'n Proto IntelliJ plugin: context-aware code completion, cross-file Ctrl+Click navigation, and automatic ordinal numbering. Four new files (1302 LOC total), one modified file (plugin.xml).

New Files

CapnpSchemaScanner.java

Regex-based scanner that extracts type definitions, constants, annotations, imports, and using-aliases from .capnp file text. Operates without a PSI tree — works directly on raw file text with comment stripping to avoid false matches.

Scanning capabilities:

  • Top-level type definitions: struct Foo, enum Bar, interface Baz (pattern anchored to 0-4 spaces indent to distinguish from nested)
  • Nested type definitions: indented struct/enum/interface inside blocks (2+ spaces or tab indent, deduplicated against top-level)
  • Constant definitions: const name :Type = value;
  • Annotation definitions: annotation name (...) :Type;
  • Import paths: plain import "path.capnp"
  • Using-import with alias: using Alias = import "path.capnp".Type
  • Using-import direct: using import "path.capnp".Type
  • Using-alias (non-import): using Alias = Scope.Type

Import resolution — 4-strategy cascade:

  1. Relative to the importing file's parent directory
  2. Relative to project content roots (ProjectRootManager.getContentRoots)
  3. Relative to module source roots (ModuleRootManager.getSourceRoots)
  4. Filename/path-suffix search across all .capnp files in the project (uses GlobalSearchScope.allScope to include library files)

Handles absolute paths (leading / stripped), normalizes for all strategies. Falls back to project-wide type collection when no imports resolve at all.

Additional robustness:

  • stripComments() removes # line comments before regex matching to prevent false positives inside commented-out code
  • getVirtualFile() null guard: falls back to getOriginalFile().getVirtualFile() for IntelliJ's in-memory completion copies where the direct virtual file reference is null
  • allScope(project) instead of projectScope(project) so that .capnp files from libraries/dependencies are also discoverable

Data classes: ScanResult, TypeInfo (kind/name/nested), ImportInfo (path/alias/specificType), AliasInfo (alias/target).

Utility methods: collectVisibleTypes(), collectProjectTypes(), collectVisibleAnnotations(), getEnumValues(), getStructFields().


CapnpCompletionContributor.java

Context-aware auto-completion registered via completion.contributor extension point. Analyzes caret position by scanning backwards through the file text to determine what kind of completion to offer.

Context detection (analyzeContext method): Scans backwards from the caret, first skipping any partial identifier the user is currently typing, then skipping whitespace, to find the preceding token:

Preceding token | Context | What is offered -- | -- | -- : | TYPE_POSITION | Built-in types + user/imported types = | VALUE_POSITION | true, false, void, inf, nan + const refs $ | ANNOTATION_REF | Annotation names from current file + imports ( after extends | EXTENDS_TYPE | Built-in + user/imported types ( after annotation decl | ANNOTATION_TARGET | struct, field, enum, enumerant, interface, method, param, annotation, const, file, * ( after List or capitalized name | TYPE_POSITION | Built-in types + user/imported types ;, {, } at depth 0 | TOP_LEVEL | struct, enum, interface, const, using, import, annotation ;, {, } at depth > 0 | BODY_LEVEL | union, group, struct, enum, interface, const, using Line start at depth 0 | TOP_LEVEL | Declaration keywords Line start at depth > 0 | BODY_LEVEL | Body keywords Fallback with preceding : on same statement | TYPE_POSITION | Types

Completion items with insert handlers:

  • List → inserts () and positions caret between parentheses
  • import → inserts ""; and positions caret between quotes
  • struct, enum, interface, const → appends trailing space

Priority ordering:

  • Built-in types: priority 100
  • Keywords: priority 90
  • Annotation names: priority 85
  • User-defined types: priority 80
  • Constants: priority 70

Built-in type names are deduplicated against user-defined types to avoid showing Text twice when a project also defines a type named Text.


CapnpGotoDeclarationHandler.java

Implements GotoDeclarationHandler to enable Ctrl+Click (and Ctrl+B) navigation from type references to their definitions.

Resolution order:

  1. Extract the identifier under the cursor via getIdentifierAt() which walks forward and backward from the offset to find word boundaries
  2. Skip built-in types and keywords (no definition to navigate to)
  3. Search the current file for a matching definition using regex patterns for struct/enum/interface, const, annotation, and enum enumerant
  4. Search imported files — iterates over all ImportInfo entries from CapnpSchemaScanner, resolves each import path, and searches the resolved file. Handles aliased imports: if using Foo = import "bar.capnp".Baz, clicking on Foo resolves to the Baz definition in bar.capnp
  5. Fallback: searches all .capnp files in the project (allScope)

Definition matching: Uses parameterized regex patterns (TYPE_DEF_LINE, CONST_DEF_LINE, ANNOTATION_DEF_LINE, ENUMERANT_LINE) where the target name is injected via Pattern.quote(). After finding a regex match, locates the exact character offset of the name within the match and returns file.findElementAt(offset). IntelliJ then opens that file and positions the cursor at the definition.


CapnpOrdinalTypedHandler.java

Implements TypedHandlerDelegate to auto-insert the next ordinal number when the user types @ after a field or enumerant name.

Trigger conditions (shouldAutoInsert):

  • Must be inside a block (brace depth > 0)
  • The character before @ (after skipping whitespace) must be the end of an identifier (field name / enumerant name / method name)
  • The character before that identifier must be a newline, {, or ; (indicating a declaration position, not a type or value context)
  • Does NOT trigger at line start (could be file ID @0xABCD), after : or =, or inside strings/comments

Scope-aware ordinal search (findMaxOrdinal):

  • Finds the enclosing { via findBlockStart() (walks backwards counting brace depth, skipping strings and comments)
  • Finds the closing } via findBlockEnd() (walks forward)
  • Scans the block for all @N patterns at depth 0 and depth 1
    • Depth ≤ 1 is intentional: Cap'n Proto ordinals share the same numbering space across a struct and its unions/groups, so @3 inside a union within a struct must be counted when determining the next ordinal for a field in the same struct
  • Explicitly skips @0x... hex patterns (type IDs, not ordinals)
  • Parses each ordinal number and tracks the maximum

Insert behavior:

  • Inserts (max + 1) as a string immediately after the @ character
  • If no ordinals exist in the block, inserts 0 (first field)
  • Moves the caret to after the inserted number
  • Returns Result.STOP to prevent further handler processing

Example flow:

struct Person {
  name @0 :Text;      # existing
  age @1 :UInt32;      # existing
  email@               # user types '@' here
  email@2              # handler auto-inserts '2', caret after '2'

Nested union example:

struct Msg {
  id @0 :UInt64;
  union {
    text @1 :Text;
    data @2 :Data;
  }
  timestamp@           # auto-inserts '3' (scans union at depth 1)

ahmetrg and others added 2 commits April 4, 2026 11:54
Updated version number from 5.0 to 4.0 and modified change notes.
@meetzli
Copy link
Copy Markdown
Contributor

meetzli commented May 9, 2026

LGTM

@xmonader
Copy link
Copy Markdown
Owner

Hi i'll do a proper review soon

@gunesahmet
Copy link
Copy Markdown
Author

gunesahmet commented May 16, 2026

Sent new code that automatically corrects the subsequent order due to new fields inserted or fields removed.

Copy link
Copy Markdown
Author

@gunesahmet gunesahmet left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Added new features and fix version

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

4 participants